////////////////////////////////////////////////////////////////
///
/// File: Emitter.m
/// Author: Lucio Davide Spano
/// Last update: 27 July 2012
/// Description: This class represent the protocol for fowarding
///              low-level device events to the gesture expression
/// To do:
/// ------------------------------------------------------------
/// Copyright (c) 2012 Lucio Davide Spano
///                     (lucio.davide.spano@isti.cnr.it)
///
/// The use and distribution terms for this software are
/// contained in the file named license.txt, which can be found
/// in the root of this distribution.
/// By using this software in any fashion, you are agreeing to
/// be bound by the terms of this license.
///
/// You must not remove this notice, or any other, from this
/// software.
/// ------------------------------------------------------------
////////////////////////////////////////////////////////////////

#import "Emitter.h"
#import "TmpExp.h"
#import "SimpleTmpExp.h"
#import "BinaryTmpExp.h"
#import "ComplexTmpExp.h"

@interface Emitter (private)
+ (NSNumber*) _getFalse;
+ (NSNumber*) _getTrue;
- (void) createLeafList:(TmpExp*) exp;
@end

@implementation Emitter (private)

static NSNumber* _false = nil;
static NSNumber* _true = nil;

+ (NSNumber*) _getFalse{
    if(_false == nil){
        _false = [[NSNumber alloc] initWithBool:NO];
    }
    return _false;
}
+ (NSNumber*) _getTrue{
    if(_true == nil){
        _true =  [[NSNumber alloc] initWithBool:YES];
    }
    return _true;
}

- (void) createLeafList:(TmpExp*) exp{
    if(exp == nil){
        return;
    }
    
    switch(exp.type){
        case Simple:{
            SimpleTmpExp* simple = (SimpleTmpExp*) exp;
            [_leafs addObject:simple];
            [_flags addObject:[Emitter _getFalse]];
        }break;
            
        case Binary:{
            BinaryTmpExp* binary = (BinaryTmpExp*) exp;
            [self createLeafList:binary.leftOperand];
            [self createLeafList:binary.rightOperand];
            
        }break;
            
        case Complex:{
            ComplexTmpExp* complex = (ComplexTmpExp*) exp;
            for(TmpExp* op in [complex getOperands]){
                [self createLeafList:op];
            }
        }break;
    }
}

@end

@implementation Emitter

- (id) init{
    self = [super init];
    if(self){
        _gesture = nil;
        _leafs = [[NSMutableArray alloc] init];
        _flags = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void) setGestureDescription:(TmpExp *)gesture{
    [_leafs removeAllObjects];
    [_flags removeAllObjects];
    _gesture = gesture;
    [self createLeafList:gesture];
}

- (void) feedDeviceEvent:(ExpEventArgs *)args{
    for(int i = 0; i < _leafs.count; i++){
        TmpExp* curr = [_leafs objectAtIndex:i];
        if(curr.state == Enabled){
            [_flags replaceObjectAtIndex:i withObject:[Emitter _getTrue]];
        }
    }
    
    bool executed = false;
    SimpleTmpExp* leafs_i = nil;
    bool flags_i = false;
    for (int i = 0; i < _leafs.count; i++) {
        leafs_i = [_leafs objectAtIndex:i];
        flags_i = [[_flags objectAtIndex:i] boolValue];
        if(flags_i && leafs_i != nil ){
            if(![leafs_i accepts:args]){
                [leafs_i notAccepted:args];
                [_flags replaceObjectAtIndex:i withObject:[Emitter _getFalse]];
            }
        }
        
    }
    for (int i = 0; i < _leafs.count; i++) {
        leafs_i = [_leafs objectAtIndex:i];
        flags_i = [[_flags objectAtIndex:i] boolValue];
        if(flags_i && leafs_i != nil ){
            [leafs_i consume:args];
            executed = true;
        }
    }
    
    if(!executed){
        for(SimpleTmpExp* s in _leafs){
            if(s.state != Disabled){
                //NSLog(@"raise error");
                [s invalidate:args];
            }
        }
    }
    time++;
}

- (void) startRecognition:(Token *)token{
    if(_gesture != nil){
        time = 0;
        [_gesture setExecState:Disabled :token];
        [_gesture setExecState:Enabled :token];
    }
}

@end
